<?php
namespace app\mxty\logic;

use think\facade\Cache;

use app\mxty\model\Course as CourseModel;
use app\mxty\model\CourseOrder as CourseOrderModel;
use app\mxty\model\CourseLesson as CourseLessonModel;
use app\api\model\Wxapp as WxappModel;
use app\mxty\model\Coach as CoachModel;
use app\api\model\User as UserModel;
use app\mxty\model\CourseLessonClockIn as CourseLessonClockInModel;
use app\mxty\model\CourseCoach as CourseCoachModel;

use think\facade\Request;
use app\common\library\wechat\WxPay;
use app\common\enum\OrderType as OrderTypeEnum;

use app\api\service\User as UserService;
use app\api\service\passport\Login as LoginService;
use app\mxty\logic\Coach as CoachLogic;

class Course
{
    public function getAllCourse()
    {
        $list = (new CourseModel())->getAll();
        // 检查开班人数是否已满
        $list = $this->checkClassSize($list);
        $list = $this->getCourseLessonsInfo($list);
        return $list->toArray();
    }

    public function checkClassSize($list)
    {
        foreach($list as $course) {
            $course->paid_nums = CourseOrderModel::countPaidNums($course->course_id);
        }

        return $list;
    }

    public function getRecommends()
    {
        $list = (new CourseModel())->getRecommends();
        return $list->toArray();
    }

    public function getCourseDetail($courseId)
    {
        $course = (new CourseModel())->findCourse($courseId);
        return $course->toArray();
    }

    public function buyCourse($courseId)
    {
        // 获取当前请求的用户信息
        $user = UserService::getCurrentLoginUser(true);
        // 检查用户是否已经购买该课程
        if($this->hasBought($user->user_id, $courseId)) {
            throwError('您已经购买过这个课程了哦');
        }
        // 查找对应课程信息
        $course = (new CourseModel())->findCourse($courseId);
        if ($course->isEmpty()) {
            throwError('课程不存在');
        }
        // 课程存在，则检查报名名额是否已满
        [$course] = $this->checkClassSize([$course]);
        if($course->paid_nums >= $course->class_size) {
            throwError('该课程报名名额已满');
        }
        // 创建订单
        $params = [
            'course_id' => $course->course_id,
            'course_name' => $course->name,
            'user_id' => $user->user_id,
            'order_no' => $this->createOrderNo(),
            'price' => $course->price,
            'image_id' => $course->image_id,
            'lessons' => $course->lessons,
            'class_hour' => $course->class_hour,
            'class_size' => $course->class_size,
            'opening_date' => $course->opening_date,
            'class_time' => $course->class_time,
            'class_place' => $course->class_place
        ];
        $order = CourseOrderModel::order($params);
        // 创建微信支付预订单
        $notifyUrl =
            Request::domain() . '/index.php/mxty/payment/buyCourseNotify';
        // 统一下单API
        $wxConfig = static::getWxConfig();
        $WxPay = new WxPay($wxConfig);
        $result = $WxPay->unifiedorder(
            $order->order_no,
            $user->open_id,
            $course->price,
            OrderTypeEnum::ORDER,
            $notifyUrl
        );
        return array_merge($result, ['appId' => $wxConfig['app_id']]);
    }

    // 检查用户是否已经购买指定课程
    public function hasBought($userId, $courseId)
    {
        $order = CourseOrderModel::hasBought($userId, $courseId);
        if($order->isEmpty()) {
            return false;
        }
        return true;
    }

    // 获取指定的课程订单信息
    public static function getOrderInfo($order_no)
    {
        $order = CourseOrderModel::getInfoByOderNo($order_no);
        return $order;
    }

    // 获取用户的所有课程
    public function getUserCourses()
    {
        // 获取当前请求的用户信息
        $user_id = UserService::getCurrentLoginUserId();
        $list = (new CourseOrderModel())->getCoursesByUserId($user_id);
        $list = $this->getCourseLessonsInfo($list);
        return $list->toArray();
    }

    // 获取教练的所有学员
    public function getCoachStudents()
    {
        $courses = $this->getCoursesByUserId();
        $coursesIds = [];
        foreach($courses as $course) {
            array_push($coursesIds, $course->course_id);
        }
        $list = (new CourseOrderModel)->getStudentsByCoursesId($coursesIds);
        foreach($list as $student) {
            $orders = $student->user->courseOrder;
            $this->getCourseLessonsInfo($orders);
        }
        return $list->toArray();
    }

    // 获取教练的所有课程及其学员
    public function getAllCoursesWithStudent()
    {
        $ids = $this->getCoachIdsByUserId();
        $courses = (new CourseOrderModel)->getCoursesByEmployeeIds($ids);
        // 获取每个课程的进度
        $list = $this->getCourseLessonsInfo($courses);
        return $list->toArray();
    }

    // 获取教练的所有课程
    public function getCoachCourses()
    {
        $courses = $this->getCoursesByUserId();
        $this->getCourseLessonsInfo($courses);
        // 查找每个课程的学员人数
        $this->getCourseStudents($courses);
        return $courses->toArray();
    }

    // 根据用户id查找其作为教练的所有课程
    public function getCoursesByUserId()
    {
        $coachIds = $this->getCoachIdsByUserId();
        // 获取多个教练id所属的所有课程id
        $courseIds = $this->getCourseIdsByCoachIds($coachIds);
        $courses = (new CourseModel)->getCourses($courseIds);
        return $courses;
    }

    // 根据多个教练id获取所属的所有课程id
    public function getCourseIdsByCoachIds($coachIds)
    {
        $list = CourseCoachModel::selectCourses($coachIds);
        $courseIds = [];
        foreach($list as $model) {
            array_push($courseIds, $model->course_id);
        }

        return $courseIds;
    }

    // 根据用户id查找他对应的所有教练id
    public function getCoachIdsByUserId()
    {
        // 获取当前请求的用户信息
        $user_id = UserService::getCurrentLoginUserId();
        // 获取该用户对应的教练id
        $coachs = CoachLogic::getCoachIdByUserId($user_id);
        
        if(empty($coachs)) {
            throwError('该用户非工作人员');
        }

        $ids = [];
        foreach($coachs as $coach) {
            array_push($ids, $coach['employee_id']);
        }
        return $ids;
    }

    // 查询每个课程的学员人数
    public function getCourseStudents($list)
    {
        foreach($list as $course) {
            $num = (new CourseOrderModel)->countStudentNum($course->course_id);
            $course->student_num = $num;
        }
    }

    /**
     * 获取每个课程最近的一次课，及其课程进度
     * $param collection $list 课程集合或者课程订单集合
     */
    public function getCourseLessonsInfo($list)
    {
        foreach($list as $course) {
            $lessons = CourseLessonModel::findLessons($course->course_id);
            $now = time();
            // 最近的一节课的上课时间
            $latest_date = 0;
            // 最近的一节课(lesson model，如果遍历后仍然是 null，则该课程没有课时或者所有设置的课时已结束)
            $latest_lesson = null;
            // 已完成的课时数量
            $completed_lessons_length = 0;
            // 遍历所有该用户的课程，找出每个课程的最近的一节课
            foreach($lessons as $lesson) {
                $lesson_time = explode('-', $lesson->class_time);
                $lesson_start_time = $lesson_time[0];
                $lesson_end_time = $lesson_time[1];

                // 该节课的开始时间
                $lesson_date_start_time = strtotime($lesson->class_date. ' ' . $lesson_start_time);
                // 该节课的结束时间
                $lesson_date_end_time = strtotime($lesson->class_date. ' ' . $lesson_end_time);
                // 该节课与当前时间的距离
                $time_diff = $lesson_date_end_time - $now;
                // 如果该节课时间未过
                if($time_diff > 0) {
                    // 比较是否为最近的一节课
                    if($lesson_date_end_time < $latest_date || $latest_lesson == null) {
                        // 记录该节课的上课时间
                        $latest_date = $lesson_date_start_time;
                        // 记录该节课为该课程的最近一节课
                        $latest_lesson = $lesson;
                    }
                }else {
                    // 该节课时间已过
                    $completed_lessons_length++;
                }
                
            }
            $course->latest_lesson = $latest_lesson;
            $course->completed_lessons_length = $completed_lessons_length;
        }

        return $list;
    }

    // 获取指定课程的所有课时及其学员信息
    public function getAllLessonsWithStudents($courseId)
    {
        // 验证请求用户的身份
        $isCoach = CoachLogic::isCoach();
        if(!$isCoach) {
            throwError('该用户非工作人员');
        }

        $list = (new CourseLessonModel)->selectAllLessons($courseId);
        $allStudents = $this->getAllStudents($courseId);
        foreach($list as $lesson) {
            $clockInStudents = $lesson->students;
            $notClockIn = $allStudents->diff($clockInStudents);
            // 当clockInStudents和$allStudents相同时，差值为空。当clockInStudents为空的时候，$allStudents->diff的结果也为空, 所以判断一下。
            if($notClockIn->isEmpty()) {
                // 判断已签到学员列表是否为空
                if($clockInStudents->isEmpty()) {
                    $notClockIn = $allStudents;
                }
            }
            $lesson->notClockIn = $notClockIn;
            
        }
        return $list->toArray();
    }

    // 获取指定课程的所有学员
    public function getAllStudents($courseId)
    {
        $list = (new CourseOrderModel)->getStudentsByCoursesId($courseId);
        $students = $list->map(function ($order) {
            return $order->user;
        });
        return $students;
    }

    // 生成二维码token
    public function generateCodeToken()
    {
        // 获取当前请求的用户信息
      $user = UserService::getCurrentLoginUser(true);
      $codeToken = (new LoginService)->makeToken($user->user_id);
      // 设置一个5分钟的缓存
      Cache::set($codeToken, $user->user_id, 300);
      return $codeToken;
    }

    // 课程二维码信息查询
    public function checkCourse($orderId, $token)
    {
        // 获取进行扫码操作的用户信息，如果未登陆会提示用户登陆
        $scanCodeUser = UserService::getCurrentLoginUser(true);
        // 验证扫码操作的用户身份，是否为工作人员
        $employee = (new CoachModel())->findEmployeeByUserId(
            $scanCodeUser->user_id
        );
        if ($employee->isEmpty()) {
            throwError('只有工作人员才能进行扫码操作哦');
        }

        // 通过该二维码token获取user_id
        $user_id = Cache::get($token);
        // 获取用户信息
        $user = UserModel::detail($user_id);
        if (!$user) {
            throwError('二维码已失效，请刷新课程二维码后重新扫码');
        }

        // 获取课程信息
        $course = (new CourseOrderModel)->getInfoByOrderIdAndUserId($orderId, $user_id);
        if($course->isEmpty()) {
            throwError('没有找到该课程信息');
        }

        // 找到最近的一节课签到
        list($course) = $this->getCourseLessonsInfo([$course]);
        // 若最近没有课时设置
        if(empty($course->latest_lesson)) {
            throwError('该课程最近没有课时哦');
        }


        $hasExists = (new CourseLessonClockInModel)->hasClockRecord($course->latest_lesson->lesson_id, $course->order_id, $course->user_id);
        if($hasExists) {
            throwError('最近一节课已经签到了哦');
        }

        return $course;
    }

    // 课程二维码签到
    public function clockIn($orderId, $token)
    {
        $course = $this->checkCourse($orderId, $token);
        // 添加签到记录
        $isCreated = (new CourseLessonClockInModel)->clockIn([
            'lesson_id' => $course->latest_lesson->lesson_id,
            'order_id' =>  $course->order_id,
            'user_id' => $course->user_id
        ]);

        if(!$isCreated) {
            throwError('最近一节课已经签到了哦');
        }

        return $isCreated;
    }

    // 最近一节课是否已经签到
    public function hasClockIn()
    {

    }

    /**
     * 获取微信支付配置
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private static function getWxConfig()
    {
        return WxappModel::getWxappCache(getStoreId());
    }

    /**
     * 生成订单号
     * @return string
     */
    public function createOrderNo()
    {
        return date('Ymd') .
            substr(
                implode(
                    null,
                    array_map('ord', str_split(substr(uniqid(), 7, 13), 1))
                ),
                0,
                11
            );
    }
}
